//
// copyright 2003 Don Kackman - mailto:dkackman_2000@yahoo.com
//
// no warranty expressed or implied
// use however you'd like
//
using System;
using System.IO;
using System.Reflection;
using System.Diagnostics;

namespace VersionVDProj
{
    /// <summary>
    /// Class representing a three or four part version string
    /// </summary>
    public class NewVersion
    {
        private string mask;
        private Version version;

        public NewVersion(string v)
        {
            if (IsVersion(v))
                version = new Version(v);

            else if (IsVersionMask(v))
                mask = v;

            else if (IsFileSpec(v))
                version = Assembly.ReflectionOnlyLoadFrom(v).GetName().Version;

            else
                throw new ArgumentException("The version does not match any of the expected formats");
        }

        public bool IsMask
        {
            get
            {
                return !string.IsNullOrEmpty(mask);
            }
        }

        public Version GetVersion(string currentVersion)
        {
            if (IsMask)
            {
                Version current = new Version(currentVersion);
                string[] maskFields = mask.Split('.');

                // we've already verified that the mask has at least three fields in the constructor
                int major = GetMaskedField(current.Major, maskFields[0]);
                int minor = GetMaskedField(current.Minor, maskFields[1]);
                int build = GetMaskedField(current.Build, maskFields[2]);

                int revision = 0;
                if (maskFields.Length == 4)
                    revision = GetMaskedField(current.Revision, maskFields[3]);

                return new Version(major, minor, build, revision);
            }

            Debug.Assert(version != null);
            return version;
        }

        private static int GetMaskedField(int current, string mask)
        {
            if (mask == "?")
                return current;

            if (mask == "+")
                return current + 1;

            int i;
            if (int.TryParse(mask, out i))
                return i;

            Debug.Assert(false);
            return 0;
        }

        private static bool IsFileSpec(string version)
        {
            string ext = Path.GetExtension(version);
            return ext.Equals(".exe", StringComparison.OrdinalIgnoreCase) || ext.Equals(".dll", StringComparison.OrdinalIgnoreCase);
        }

        private static bool IsVersionMask(string version)
        {
            string[] tmp = version.Split('.');

            if (tmp.Length != 3 && tmp.Length != 4)
                return false;

            if (!version.Contains("+") && !version.Contains("?"))
                return false;

            try
            {
                foreach (string s in tmp)
                {
                    if (s != "?" && s != "+" && !StringIsVersionInt(s))
                        return false;
                }
            }
            catch (FormatException)
            {
                return false;
            }

            return true;
        }


        private static bool IsVersion(string version)
        {
            string[] tmp = version.Split(new char[] { '.' });

            if (tmp.Length != 3 && tmp.Length != 4)
                return false;

            try
            {
                // loop through each member of the split array and make sure it's numeric
                foreach (string s in tmp)
                {
                    if (!StringIsVersionInt(s))
                        return false;
                }
            }
            catch (FormatException)
            {
                return false;
            }

            return true;
        }

        private static bool StringIsVersionInt(string s)
        {
            int i;
            return int.TryParse(s, out i) && i >= 0;
        }
    }
}
